import sys
import json
import drive
import config
import keyboard
import mouse
import pygame
import time
import threading
from PyQt6.QtWidgets import QApplication, QGraphicsDropShadowEffect, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSpacerItem, QSizePolicy, QRadioButton, QComboBox
from PyQt6.QtGui import QIcon, QColor
from PyQt6.QtCore import Qt, QSize

# 主窗口类
class DDKeySimulator(QWidget):
    """初始化按键模拟器"""
    def __init__(self):
        super().__init__()
        self.lock = threading.Lock()
        self.load_cached()  # 加载缓存的键码和配置
        self.init_ui()  # 初始化用户界面
        pygame.mixer.init()  # 初始化 pygame

    """加载缓存配置"""
    def load_cached(self):
        try:
            with open(config.CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
            self.cached_exe_keys = cache_data.get('EXE_KEYS', "")  # 加载缓存的执行键名
            self.swi_key = cache_data.get('swi_key', "f1")  # 加载缓存的开关键名
            self.cached_key_delay = cache_data.get('KEY_DELAY', str(config.key_delay))  # 加载缓存的延迟
            config.key_mode = cache_data.get("KEY_MODE")
        except (FileNotFoundError, json.JSONDecodeError):
            self.cached_exe_keys = ""
            self.swi_key = "f1"
            self.cached_key_delay = str(config.key_delay)

    """前端"""
    def init_ui(self):
        self.setWindowTitle("滴斗按键")
        self.resize(250, 200)  # 设置窗口大小为 330x280
        # self.setFixedSize(310, 250)  # 设置窗口固定大小
        # 设置窗口背景为透明
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        # self.setAttribute(Qt.WA_TranslucentBackground)
        # 设置窗口无边框
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        # self.setWindowFlags(Qt.FramelessWindowHint)
        self.setStyleSheet(
            """
            font-size: 12px;
            """
        )

        # 创建阴影效果
        shadow_effect = QGraphicsDropShadowEffect(self)
        shadow_effect.setBlurRadius(10)  # 阴影模糊半径
        shadow_effect.setOffset(0, 0)  # 阴影偏移
        shadow_effect.setColor(QColor(0, 0, 0, 100))  # 阴影颜色

        # 应用阴影效果到窗口主体
        self.setGraphicsEffect(shadow_effect)

        # 使用 config.resource_path 函数来获取图标文件的路径
        icon_path = config.resource_path("didou.ico")
        self.setWindowIcon(QIcon(icon_path))

        self.custom_title_bar = config.CustomTitleBar(self)  # 创建自定义标题栏
        
        self.label = QLabel("滴斗滴斗！", self)
        self.label.setStyleSheet("QLabel { font-family: 'Microsoft YaHei'; }")

        self.text_edit = config.CenteredTextEdit(self)  # 创建居中文本编辑框
        self.text_edit.setPlaceholderText("输入按键\n(每行一个)")  # 设置占位符文本
        self.text_edit.setMaximumWidth(300)  # 设置最大宽度
        self.text_edit.setPlainText(self.cached_exe_keys)  # 设置初始文本

        self.main_switch_button = QPushButton(self)
        self.main_switch_button.setIcon(QIcon(f'{config.of_icon_path()}'))  # 设置图标，使用图标文件路径
        self.main_switch_button.setIconSize(QSize(16, 16))
        self.main_switch_button.setStyleSheet(
            """
            QPushButton {
                background-color: rgba(100, 100, 100, 30); /* 半透明背景 */
                width: 18px; 
                border-radius: 4px;
                padding: 5px;
            }
            QPushButton:hover { 
                background-color: rgba(100, 100, 100, 40); /* 半透明背景 */
            }
            QPushButton:pressed { 
                background-color: rgba(100, 100, 100, 40); /* 背景 */
                padding-left: 6px; /* 增加内边距 */
                padding-top: 6px; /* 增加内边距 */
            }
            """
        )
        size_policy = self.main_switch_button.sizePolicy()  # 设置垂直策略为 Preferred
        size_policy.setVerticalPolicy(QSizePolicy.Policy.Preferred)
        self.main_switch_button.setSizePolicy(size_policy)  # 垂直拉满
        self.main_switch_button.clicked.connect(self.main_switch)  # 连接点击事件到处理方法

        self.input_label = QLabel("ms  ", self)  # 输入延迟标签
        self.input_label.setStyleSheet("QLabel { font-family: 'Microsoft YaHei'; }")

        self.input_box = QLineEdit(self)  # 输入框
        size_policy = self.input_box.sizePolicy()  # 设置垂直策略为 Preferred
        size_policy.setVerticalPolicy(QSizePolicy.Policy.Preferred)
        self.input_box.setSizePolicy(size_policy)  # 垂直拉满
        self.input_box.setStyleSheet(
            """
            QLineEdit {
                font-family: 'Microsoft YaHei';
                background-color: rgba(100, 100, 100, 0); /* 半透明背景 */
                border-radius: 4px;
                padding: 5px;
                padding-left: 10px;
                padding-right: 10px;
            }
            """
        )
        self.input_box.setPlaceholderText("输入延迟")  # 设置占位符文本
        # self.input_box.setAlignment(Qt.AlignCenter) # 设置文本居中
        self.input_box.setText(self.cached_key_delay)  # 设置初始文本
        self.input_box.textChanged.connect(self.validate_input)  # 连接文本变化事件到验证方法

        # 创建模式切换按钮  
        self.mode_button = QPushButton(f"{config.key_mode}",self) # 创建模式切换按钮
        size_policy = self.mode_button.sizePolicy()  # 设置垂直策略为 Preferred
        size_policy.setVerticalPolicy(QSizePolicy.Policy.Preferred)
        self.mode_button.setSizePolicy(size_policy)  # 垂直拉满
        self.mode_button.clicked.connect(self.key_mode_changed)  # 连接点击事件到处理方法
        self.mode_button.setStyleSheet(
            """
            QPushButton {
                font-family: 'Microsoft YaHei';
                background-color: rgba(66, 133, 244, 1); /* 背景 */
                color: rgba(255, 255, 255, 255);
                border-radius: 4px;
                padding: 5px;
            }
            QPushButton:hover { 
                background-color: rgba(60, 130, 240, 1); /* 背景 */
            }
            QPushButton:pressed { 
                background-color: rgba(60, 130, 240, 1); /* 背景 */
                padding-left: 7px; /* 增加内边距 */
                padding-top: 7px; /* 增加内边距 */
            }
            QPushButton:disabled {
                color: rgba(200, 200, 200, 255);
            }
            """
        )
        # 创建阴影效果
        m_btn_shadow = QGraphicsDropShadowEffect()
        m_btn_shadow.setBlurRadius(8)  # 设置阴影模糊度
        m_btn_shadow.setXOffset(0)  # 设置阴影的水平偏移
        m_btn_shadow.setYOffset(0)  # 设置阴影的垂直偏移
        m_btn_shadow.setColor(QColor(100, 50, 0, 120))  # 设置阴影颜色（黑色，带透明度）
        # 将阴影效果应用到按钮
        self.mode_button.setGraphicsEffect(m_btn_shadow)

        self.key_button = QPushButton(f"设置开关：{self.swi_key}", self)  # 设置开关按钮
        # 设置垂直策略为 Preferred
        size_policy = self.key_button.sizePolicy()
        size_policy.setVerticalPolicy(QSizePolicy.Policy.Preferred)
        self.key_button.setSizePolicy(size_policy)
        self.key_button.setStyleSheet(
            """
            QPushButton {
                font-family: 'Microsoft YaHei';
                background-color: rgba(251, 188, 5, 255); /* 背景 */
                border-radius: 4px;
                padding: 5px;
            }
            QPushButton:hover { 
                background-color: rgba(250, 180, 5, 255); /* 背景 */
            }
            QPushButton:pressed { 
                background-color: rgba(250, 180, 5, 255); /* 背景 */
                padding-left: 7px; /* 增加内边距 */
                padding-top: 7px; /* 增加内边距 */
            }
            """
        )
        # 创建阴影效果
        k_btn_shadow = QGraphicsDropShadowEffect()
        k_btn_shadow.setBlurRadius(8)  # 设置阴影模糊度
        k_btn_shadow.setXOffset(0)  # 设置阴影的水平偏移
        k_btn_shadow.setYOffset(0)  # 设置阴影的垂直偏移
        k_btn_shadow.setColor(QColor(100, 50, 0, 120))  # 设置阴影颜色（黑色，带透明度）
        # 将阴影效果应用到按钮
        self.key_button.setGraphicsEffect(k_btn_shadow)
        self.key_button.clicked.connect(self.key_change_thr)  # 连接点击事件到处理方法

        self.author_label = QLabel("by—花无衣", self)  # 作者标签
        self.author_label.setStyleSheet("QLabel { font-family: 'Microsoft YaHei'; color: #999999; }")

        self.version_label = QLabel(f"{config.version}", self)  # 版本标签
        self.version_label.setStyleSheet("QLabel { font-family: 'Microsoft YaHei'; color: #999999; }")

        # 布局代码放在一起
        main_widget = QWidget()
        main_widget.setObjectName("main_widget")
        main_v_layout = QVBoxLayout(main_widget)  # 创建主垂直布局
        main_v_layout.setContentsMargins(0, 0, 0, 0)  # 增加布局边距显示阴影
        main_v_layout.setSpacing(0)  # 设置布局间距为 0

        main_v_layout.addWidget(self.custom_title_bar)  # 添加自定义标题栏

        # 创建一个新的 QWidget 作为 master_v_layout 的容器
        master_widget = QWidget()
        master_widget.setObjectName("master_widget")
        master_v_layout = QVBoxLayout(master_widget)  # 创建主界面垂直布局
        master_v_layout.setContentsMargins(10, 5, 10, 5)  # 设置布局边距
        master_v_layout.setSpacing(6)  # 设置布局间距为 5

        master_v_layout.addWidget(self.label)  # 添加标签 滴斗滴斗!

        h_layout = QHBoxLayout()  # 创建水平布局

        h_layout.addWidget(self.text_edit, 5)  # 添加文本编辑框

        input_widget = QWidget()
        input_widget.setObjectName("input_widget")
        input_widget.setStyleSheet(
            """
            #input_widget {
                max-width: 105px; 
                background-color: rgba(100, 100, 100, 30); /* 半透明背景 */
                border-radius: 4px;
                padding: 5px;
                padding-left: 10px;
                padding-right: 10px;
                /* min-width: 85px;  */
            }
            """
        )
        input_layout = QHBoxLayout(input_widget)  # 创建输入框水平布局
        input_layout.setContentsMargins(0, 0, 0, 0)  # 设置布局边距
        input_layout.addWidget(self.input_box)
        input_layout.addWidget(self.input_label)

        h1_layout = QHBoxLayout()  # 创建水平布局1
        h1_layout.setSpacing(5)  # 设置布局间距为 0
        h1_layout.addWidget(self.main_switch_button)
        h1_layout.addWidget(input_widget)

        right_v_layout = QVBoxLayout()  # 创建右侧垂直布局

        # right_v_layout.addStretch()  # 添加伸缩空间
        # right_v_layout.addWidget(self.input_label)  # 添加标签
        right_v_layout.addLayout(h1_layout)
        right_v_layout.addWidget(self.mode_button)  # 模式选择
        right_v_layout.addWidget(self.key_button)  # 添加按钮


        hb_layout = QHBoxLayout()  # 创建底部水平布局
        hb_layout.addWidget(self.version_label, alignment=Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignLeft)  # 添加标签并左下对齐
        hb_layout.addWidget(self.author_label, alignment=Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignRight)  # 添加标签并右下对齐

        h_layout.addLayout(right_v_layout, 5)  # 添加右侧布局
        master_v_layout.addLayout(h_layout)  # 添加水平布局
        master_v_layout.addLayout(hb_layout)  # 添加底部水平布局

        # 为 master_widget 设置样式表以添加背景样式
        main_widget.setStyleSheet("""
            #main_widget {
                background-color: rgba(255, 255, 255, 1);
                border-radius: 8px;  /* 圆角 */
            }
        """)

        # 将 master_widget 添加到主布局中，并确保它不会被其他组件继承样式
        main_v_layout.addWidget(master_widget)

        outer_layout = QVBoxLayout()  # 创建一个外层布局
        outer_layout.addWidget(main_widget)  # 将 main_widget 添加到外层布局
        self.setLayout(outer_layout)  # 设置主窗口的布局

    """点击按钮切换按键模式"""
    def key_mode_changed(self):
        if config.key_mode == "开关模式":
            config.key_mode = "按压模式"
            print("切换为按压模式")
        elif config.key_mode == "按压模式":
            config.key_mode = "目标按压"
            print("切换为目标按压")
        else:
            config.key_mode = "开关模式"
            print("切换为开关模式")
            
        self.mode_button.setText(f"{config.key_mode}")
    
    """点击按钮创建更改启停键线程"""
    def key_change_thr  (self):
        thread = threading.Thread(target=self.change_switch)  # 创建模拟线程
        thread.start()  # 启动线程
    
    """按下总开关按钮"""
    def main_switch(self):
        if config.swi_thr == True:
            config.swi_thr = False
            config.swi_dd = False
            print(f"总开关：{config.swi_thr}   按键开关：{config.swi_thr}   目标开关：{config.swi_vars}")
            config.swi_vars = {}

            """"启用控件"""
            self.text_edit.setEnabled(True)
            self.input_box.setEnabled(True)
            self.input_label.setEnabled(True)
            self.mode_button.setEnabled(True)
            self.key_button.setEnabled(True)

            # config.play_sound('stop.mp3')
            keyboard.unhook_all()  # 取消所有键盘监听
            mouse.unhook_all()  # 取消所有鼠标监听
            print("已取消所有现有监听")

        else:
            config.swi_thr = True

            """"禁用控件"""
            self.text_edit.setEnabled(False)
            self.input_box.setEnabled(False)
            self.input_label.setEnabled(False)
            self.mode_button.setEnabled(False)
            self.key_button.setEnabled(False)

            print("线程开关：True")
            
            # 确保监听器被正确停止
            keyboard.unhook_all()
            mouse.unhook_all()

            self.label.setText("滴斗滴斗！")  # 设置标签文本
            self.key_names = self.get_key_names()  # 获取键名列表
            for key_name in self.key_names:
                if key_name not in drive.dd_key:
                    self.show_error(f"无效的键名: {key_name}")  # 显示错误信息

            if config.key_mode == "开关模式" or config.key_mode == "按压模式":
                if self.swi_key == "Mx" or self.swi_key == "Mx2":
                    mouse.hook(self.on_mouse_event)
                else:
                    keyboard.hook_key(self.swi_key, self.on_key_event)  # 开启监听目标按键

            elif config.key_mode == "目标按压":
                config.swi_vars = {f"{name}": 0 for name in self.key_names}
                keyboard.hook(self.on_keys_event)
                mouse.hook(self.on_mouse_event)
        
        self.main_switch_button.setIcon(QIcon(f'{config.of_icon_path()}'))  # 设置图标，使用图标文件路径

    """模拟循环"""
    def sim(self, key_name):
        if self.validate_input() == False:  # 验证输入是否为数字
            return
        
        if key_name == self.swi_key.lower() and config.key_mode != "目标按压":  # 如果是目标按键，则不模拟
            self.show_error(f"冲突按键{key_name}")
            print(f"错误：目标键 {key_name} 冲突，线程启动失败")
            return 
        
        key_code = drive.dd_key[key_name]  # 获取对应的键码
        print(f"模拟按键线程 {key_name} 启动({config.key_mode})")  # 记录线程停止

        key_delay = float(self.input_box.text()) / 1000  # 计算按键延迟

        while config.swi_thr:
            if config.key_mode == "目标按压":
                swi = config.swi_vars[key_name]
            else:
                swi = config.swi_dd
            if swi:
                try:
                    if key_name in ["lb", "rb", "mid", "mx", "mx2"]:
                        drive.simulate_btn(key_code)  # 模拟鼠标
                    else:
                        drive.simulate_key(key_code)  # 模拟按键
                except Exception as e:
                    print(f"模拟按键失败: {e}")  # 记录错误
                    break
            else:
                break
            time.sleep(key_delay)  # 延迟
        print(f"模拟按键线程 {key_name} 已停止")  # 记录线程停止
        config.thr_sta.remove(key_name)
        # self.label.setText("滴斗滴斗！")  # 设置标签文本

    """键盘开关单键监听"""
    def on_key_event(self, event):
        if config.key_mode == "开关模式": # 开关模式
            if event.event_type == "down":
                if config.swi_dd:
                    config.swi_dd = False
                    config.play_sound('off.mp3')
                else:
                    config.swi_dd = True
                    config.play_sound('on.mp3')

                print(f"{event.name} {event.event_type} 开关状态: {config.swi_dd}")
        elif config.key_mode == "按压模式":  # 按压模式
            if event.event_type == "up":
                config.swi_dd = False
            elif event.event_type == "down":
                config.swi_dd = True

            print(f"{event.name} {event.event_type} 开关状态: {config.swi_dd}")
        
        if config.swi_dd:
            for key_name in self.key_names:
                self.run_thr(key_name)

    """键盘开关全键监听（目标按压模式专用）"""
    def on_keys_event(self, event):
        key_name = str(event.name).lower()
        if key_name in self.key_names:
            if event.event_type == "down":
                config.swi_vars[key_name] = 2
                print(key_name, config.swi_vars[key_name], event.event_type)
            elif event.event_type == "up":
                config.swi_vars[key_name] -= 1
                print(key_name, config.swi_vars[key_name], event.event_type)
            
            if config.swi_vars[key_name]:
                self.run_thr(key_name)

    """鼠标开关按键监听"""
    def on_mouse_event(self, event):
        if isinstance(event, mouse.MoveEvent) or isinstance(event, mouse.WheelEvent):
            return  # 忽略移动、滚轮滚动事件
        else:
            if hasattr(event, 'event_type'):
                if config.key_mode == "开关模式" or config.key_mode == "按压模式":
                    if event.button == self.swi_key[1:]:
                        if config.key_mode == "开关模式": # 开关模式
                            if event.event_type == "down" or event.event_type == "double":
                                if config.swi_dd:
                                    config.swi_dd = False
                                    config.play_sound('off.mp3')
                                else:
                                    config.swi_dd = True
                                    config.play_sound('on.mp3')
                                print(f"{event.button} {event.event_type} 开关状态: {config.swi_dd}")
                        elif config.key_mode == "按压模式":  # 按压模式
                            if event.event_type == "down" or event.event_type == "double":
                                config.swi_dd = True
                            elif event.event_type == "up":
                                config.swi_dd = False
                            print(f"{event.button} {event.event_type} 开关状态: {config.swi_dd}")
                
                    if config.swi_dd:
                        for key_name in self.key_names:
                            self.run_thr(key_name)

                elif config.key_mode == "目标按压":  # 目标按压
                    if event.button == "x" or event.button == "x2":
                        key_name = "m" + str(event.button)
                    elif event.button == "middle":
                        key_name = "mid"
                    elif event.button == "left" or event.button == "right":
                        key_name = str(event.button)[0] + "b"

                    if key_name in self.key_names:
                        if event.event_type == "down" or event.event_type == "double":
                            config.swi_vars[key_name] = 2
                            print(key_name, config.swi_vars[key_name], event.event_type)
                        elif event.event_type == "up":
                            config.swi_vars[key_name] -= 1
                            print(key_name, config.swi_vars[key_name], event.event_type)
                
                        if config.swi_vars[key_name]:
                            self.run_thr(key_name)
    
    """创建线程执行模拟方法"""
    def run_thr(self, key_name):
        if key_name in drive.dd_key and key_name not in config.thr_sta:
            thread = threading.Thread(target=self.sim, args=(key_name,), daemon=True)  # 创建模拟线程
            thread.start()  # 启动线程
            config.thr_sta.append(key_name)  # 记录运行线程
        else:
            if key_name not in drive.dd_key:
                self.show_error(f"无效的键名: {key_name}")  # 显示错误信息

    """获取键名列表"""
    def get_key_names(self):
        text = self.text_edit.toPlainText().strip()
        return [line.strip().lower() for line in text.split('\n') if line.strip()]  # 获取键名列表

    """监听延迟输入框，并进行验证是否为数字"""
    def validate_input(self):
        try:
            value = int(self.input_box.text())
            if not (0 < value):
                raise ValueError
            self.label.setText("滴斗滴斗！")  # 设置标签文本
            return True
        except:
            self.show_error("延迟必须为大于零的整数")
            return False
        
    """信息显示"""
    def show_error(self, message):
        self.label.setText(f"错误: {message}")  # 设置标签文本为错误信息

    """更改启停键"""    
    def change_switch(self):
        keyboard.unhook_all()
        mouse.unhook_all()
        print("已取消所有现有键盘监听")
        
        self.label.setText("按下键盘任意键设置为开关！")  # 设置标签文本

        def on_key_event(event):
            if self.stop_listening:
                return  # 如果已经停止监听，直接返回
                
            print(f"按键名称: {event.name}, 键码: {event.scan_code}, 事件类型: {event.event_type}")  # 记录按键事件
            self.stop_listening = True
            if event.scan_code > 1:
                self.swi_key = str(event.name).upper()  # 设置目标按键
                self.key_button.setText(f"设置开关：{self.swi_key}")  # 设置按钮文本
                print(f"开关更改为{self.swi_key}")

        def on_mouse_event(event):
            if self.stop_listening:
                return  # 如果已经停止监听，直接返回
            
            if isinstance(event, mouse.MoveEvent) or isinstance(event, mouse.WheelEvent):
                return  # 忽略移动、滚轮滚动事件
            else:
                if event.button in ("x", "x2"):  # 只处理 X 和 X2 按钮
                    self.swi_key = f"M{event.button}"  # 设置目标按键
                    self.key_button.setText(f"设置开关：{self.swi_key}")  # 更新按钮文本
                    print(f"开关更改为 {self.swi_key}")

                    self.stop_listening = True  # 停止监听

        self.stop_listening = False

        # 启动键盘监听器
        keyboard.hook(on_key_event)

        # 监听鼠标所有事件
        mouse.hook(on_mouse_event)

        print("按下键盘任意键设置为开关")
        print("监听中，按下任意键退出")

        while not self.stop_listening:
            time.sleep(0.1)  # 等待

        keyboard.unhook_all()  # 取消所有键盘监听
        mouse.unhook_all()  # 取消所有键盘监听
        print("已退出监听")

        # self.didou_event()  # 重新设置按键监听事件
        # print("已恢复原始监听")

        self.label.setText("滴斗滴斗！")  # 设置标签文本

    """Qt事件机制"""
    """鼠标点击清除输入框焦点"""
    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self.text_edit.clearFocus()  # 清除文本编辑框的焦点
            self.input_box.clearFocus()  # 清除输入框的焦点
        super().mousePressEvent(event)
    
    """关闭窗口触发事件"""
    def closeEvent(self, event):
        config.swi_dd = False  # 停止所有模拟
        print("应用正在关闭，停止所有模拟")

        keyboard.unhook_all()
        mouse.unhook_all()
        print("监听器已停止")

        try:
            with open(config.CACHE_FILE, 'r') as f:
                cache_data = json.load(f)
        except (FileNotFoundError, json.JSONDecodeError):
            cache_data = {}

        cache_data['EXE_KEYS'] = self.text_edit.toPlainText().strip()  # 执行键名

        cache_data['KEY_DELAY'] = self.input_box.text().strip()  # 延迟

        cache_data['swi_key'] = self.swi_key  # 开关键名

        cache_data['KEY_MODE'] = config.key_mode  # 开关模式

        with open(config.CACHE_FILE, 'w') as f:
            json.dump(cache_data, f, indent=4)  # 写入缓存文件

        event.accept()  # 接受关闭事件
    
if __name__ == "__main__":
    # os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"   # 关闭自动缩放（部分版本有效）
    # os.environ["QT_SCALE_FACTOR"] = "1"             # 强制1倍缩放[3,5](@ref)
    # os.environ["QT_SCREEN_SCALE_FACTORS"] = "1;1"   # 多显示器统一缩放[3](@ref)
    app = QApplication(sys.argv)
    simulator = DDKeySimulator()
    simulator.show()
    sys.exit(app.exec())